//
// Copyright (C) [2020] Futurewei Technologies, Inc.
//
// FORCE-RISCV is licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR
// FIT FOR A PARTICULAR PURPOSE.
// See the License for the specific language governing permissions and
// limitations under the License.
//

/*  !!! NOTICE !!!
    This file is automatically generated by the script: utils/enum_classes/create_enum_files.py
    Please do not modify this file manually.  Instead, modify the above mentioned script to re-generate this file.
*/

#include "Force_Enums.h"
#include <sstream>
#include <iostream>
#include <cassert>

using namespace std;

namespace Force {


  /*!
    Report an unknown enum value of the type name given in enum_type_name parameter, by throwing an EnumTypeError exception.
  */
  static void unknown_enum_value(const string& enum_type_name, unsigned long long value)
  {
    stringstream err_stream;
    err_stream << "Unknown " << enum_type_name << " enum value: " << dec << value;
    assert(false && err_stream);
    //throw EnumTypeError(err_stream.str());
  }

  /*!
    Report an unknown enum name of the type name given in enum_type_name parameter, by throwing an EnumTypeError exception.
  */
  static void unknown_enum_name(const string& enum_type_name, const string& enum_name)
  {
    stringstream err_stream;
    err_stream << "Unknown " << enum_type_name << " enum name: " << enum_name;
    assert(false && err_stream);
    //throw EnumTypeError(err_stream.str());
  }

  /*!
    Throw an exception if in_str and enum_name are not identical.
  */
  static void validate(const string& specified_enum_name, const string& expected_enum_name, const string& enum_type_name)
  {
    if (specified_enum_name != expected_enum_name) {
      unknown_enum_name(enum_type_name, specified_enum_name);
    }
  }

  unsigned char ELimitTypeSize = 12;

  const string ELimitType_to_string(ELimitType in_enum)
  {
    switch(in_enum) {
    case ELimitType::ThreadsLimit: return "ThreadsLimit";
    case ELimitType::CoresLimit: return "CoresLimit";
    case ELimitType::ChipsLimit: return "ChipsLimit";
    case ELimitType::PhysicalAddressLimit: return "PhysicalAddressLimit";
    case ELimitType::MaxInstructions: return "MaxInstructions";
    case ELimitType::PerMonRegisterNumber: return "PerMonRegisterNumber";
    case ELimitType::DependencyHistoryLimit: return "DependencyHistoryLimit";
    case ELimitType::BranchNotTakenLimit: return "BranchNotTakenLimit";
    case ELimitType::SpeculativeBntLevelLimit: return "SpeculativeBntLevelLimit";
    case ELimitType::ErrRegisterNumber: return "ErrRegisterNumber";
    case ELimitType::SpeculativeBntInstructionLimit: return "SpeculativeBntInstructionLimit";
    default:
      unknown_enum_value("ELimitType", (unsigned char)(in_enum));
    }
    return "";
  }

  ELimitType string_to_ELimitType(const string& in_str)
  {
    string enum_type_name = "ELimitType";
    size_t size = in_str.size();
    char hash_value = in_str.at(1 < size ? 1 : 1 % size) ^ in_str.at(20 < size ? 20 : 20 % size);

    switch(hash_value) {
    case 0:
      validate(in_str, "BranchNotTakenLimit", enum_type_name);
      return ELimitType::BranchNotTakenLimit;
    case 1:
      validate(in_str, "ThreadsLimit", enum_type_name);
      return ELimitType::ThreadsLimit;
    case 12:
      validate(in_str, "DependencyHistoryLimit", enum_type_name);
      return ELimitType::DependencyHistoryLimit;
    case 18:
      validate(in_str, "MaxInstructions", enum_type_name);
      return ELimitType::MaxInstructions;
    case 19:
      validate(in_str, "SpeculativeBntInstructionLimit", enum_type_name);
      return ELimitType::SpeculativeBntInstructionLimit;
    case 25:
      validate(in_str, "SpeculativeBntLevelLimit", enum_type_name);
      return ELimitType::SpeculativeBntLevelLimit;
    case 32:
      validate(in_str, "ErrRegisterNumber", enum_type_name);
      return ELimitType::ErrRegisterNumber;
    case 43:
      validate(in_str, "ChipsLimit", enum_type_name);
      return ELimitType::ChipsLimit;
    case 44:
      validate(in_str, "CoresLimit", enum_type_name);
      return ELimitType::CoresLimit;
    case 53:
      validate(in_str, "PerMonRegisterNumber", enum_type_name);
      return ELimitType::PerMonRegisterNumber;
    case 56:
      validate(in_str, "PhysicalAddressLimit", enum_type_name);
      return ELimitType::PhysicalAddressLimit;
    default:
      unknown_enum_name(enum_type_name, in_str);
    }
    return ELimitType::ThreadsLimit;
  }

  ELimitType try_string_to_ELimitType(const string& in_str, bool& okay)
  {
    okay = true;
    size_t size = in_str.size();
    char hash_value = in_str.at(1 < size ? 1 : 1 % size) ^ in_str.at(20 < size ? 20 : 20 % size);

    switch(hash_value) {
    case 0:
      okay = (in_str == "BranchNotTakenLimit");
      return ELimitType::BranchNotTakenLimit;
    case 1:
      okay = (in_str == "ThreadsLimit");
      return ELimitType::ThreadsLimit;
    case 12:
      okay = (in_str == "DependencyHistoryLimit");
      return ELimitType::DependencyHistoryLimit;
    case 18:
      okay = (in_str == "MaxInstructions");
      return ELimitType::MaxInstructions;
    case 19:
      okay = (in_str == "SpeculativeBntInstructionLimit");
      return ELimitType::SpeculativeBntInstructionLimit;
    case 25:
      okay = (in_str == "SpeculativeBntLevelLimit");
      return ELimitType::SpeculativeBntLevelLimit;
    case 32:
      okay = (in_str == "ErrRegisterNumber");
      return ELimitType::ErrRegisterNumber;
    case 43:
      okay = (in_str == "ChipsLimit");
      return ELimitType::ChipsLimit;
    case 44:
      okay = (in_str == "CoresLimit");
      return ELimitType::CoresLimit;
    case 53:
      okay = (in_str == "PerMonRegisterNumber");
      return ELimitType::PerMonRegisterNumber;
    case 56:
      okay = (in_str == "PhysicalAddressLimit");
      return ELimitType::PhysicalAddressLimit;
    default:
      okay = false;
      return ELimitType::ThreadsLimit;
    }
    return ELimitType::ThreadsLimit;
  }

  unsigned char EMemDataTypeSize = 4;

  const string EMemDataType_to_string(EMemDataType in_enum)
  {
    switch(in_enum) {
    case EMemDataType::Init: return "Init";
    case EMemDataType::Instruction: return "Instruction";
    case EMemDataType::Data: return "Data";
    case EMemDataType::Both: return "Both";
    default:
      unknown_enum_value("EMemDataType", (unsigned char)(in_enum));
    }
    return "";
  }

  EMemDataType string_to_EMemDataType(const string& in_str)
  {
    string enum_type_name = "EMemDataType";
    size_t size = in_str.size();
    char hash_value = in_str.at(4 < size ? 4 : 4 % size);

    switch(hash_value) {
    case 66:
      validate(in_str, "Both", enum_type_name);
      return EMemDataType::Both;
    case 68:
      validate(in_str, "Data", enum_type_name);
      return EMemDataType::Data;
    case 73:
      validate(in_str, "Init", enum_type_name);
      return EMemDataType::Init;
    case 114:
      validate(in_str, "Instruction", enum_type_name);
      return EMemDataType::Instruction;
    default:
      unknown_enum_name(enum_type_name, in_str);
    }
    return EMemDataType::Init;
  }

  EMemDataType try_string_to_EMemDataType(const string& in_str, bool& okay)
  {
    okay = true;
    size_t size = in_str.size();
    char hash_value = in_str.at(4 < size ? 4 : 4 % size);

    switch(hash_value) {
    case 66:
      okay = (in_str == "Both");
      return EMemDataType::Both;
    case 68:
      okay = (in_str == "Data");
      return EMemDataType::Data;
    case 73:
      okay = (in_str == "Init");
      return EMemDataType::Init;
    case 114:
      okay = (in_str == "Instruction");
      return EMemDataType::Instruction;
    default:
      okay = false;
      return EMemDataType::Init;
    }
    return EMemDataType::Init;
  }

  unsigned char EMemAccessTypeSize = 4;

  const string EMemAccessType_to_string(EMemAccessType in_enum)
  {
    switch(in_enum) {
    case EMemAccessType::Unknown: return "Unknown";
    case EMemAccessType::Read: return "Read";
    case EMemAccessType::Write: return "Write";
    case EMemAccessType::ReadWrite: return "ReadWrite";
    default:
      unknown_enum_value("EMemAccessType", (unsigned char)(in_enum));
    }
    return "";
  }

  EMemAccessType string_to_EMemAccessType(const string& in_str)
  {
    string enum_type_name = "EMemAccessType";
    size_t size = in_str.size();
    char hash_value = in_str.at(4 < size ? 4 : 4 % size);

    switch(hash_value) {
    case 82:
      validate(in_str, "Read", enum_type_name);
      return EMemAccessType::Read;
    case 87:
      validate(in_str, "ReadWrite", enum_type_name);
      return EMemAccessType::ReadWrite;
    case 101:
      validate(in_str, "Write", enum_type_name);
      return EMemAccessType::Write;
    case 111:
      validate(in_str, "Unknown", enum_type_name);
      return EMemAccessType::Unknown;
    default:
      unknown_enum_name(enum_type_name, in_str);
    }
    return EMemAccessType::Unknown;
  }

  EMemAccessType try_string_to_EMemAccessType(const string& in_str, bool& okay)
  {
    okay = true;
    size_t size = in_str.size();
    char hash_value = in_str.at(4 < size ? 4 : 4 % size);

    switch(hash_value) {
    case 82:
      okay = (in_str == "Read");
      return EMemAccessType::Read;
    case 87:
      okay = (in_str == "ReadWrite");
      return EMemAccessType::ReadWrite;
    case 101:
      okay = (in_str == "Write");
      return EMemAccessType::Write;
    case 111:
      okay = (in_str == "Unknown");
      return EMemAccessType::Unknown;
    default:
      okay = false;
      return EMemAccessType::Unknown;
    }
    return EMemAccessType::Unknown;
  }

  unsigned char EMemBankTypeSize = 1;

  const string EMemBankType_to_string(EMemBankType in_enum)
  {
    switch (in_enum) {
    case EMemBankType::Default: return "Default";
    default:
      unknown_enum_value("EMemBankType", (unsigned char)(in_enum));
    }
    return "";
  }

  EMemBankType string_to_EMemBankType(const string& in_str)
  {
    string enum_type_name = "EMemBankType";
    char hash_value = in_str.at(0);

    switch (hash_value) {
    case 68:
      validate(in_str, "Default", enum_type_name);
      return EMemBankType::Default;
    default:
      unknown_enum_name(enum_type_name, in_str);
    }
    return EMemBankType::Default;
  }

  EMemBankType try_string_to_EMemBankType(const string& in_str, bool& okay)
  {
    okay = true;
    char hash_value = in_str.at(0);

    switch (hash_value) {
    case 68:
      okay = (in_str == "Default");
      return EMemBankType::Default;
    default:
      okay = false;
      return EMemBankType::Default;
    }
    return EMemBankType::Default;
  }

}
